# unittests for TarjanMap

import unittest
import TarjanMap
from TarjanObservable import TarjanObservable
from TarjanDirection import Directions

# Requirements:

# - map.getCell(x, y) should return the cell at x, y
# - cell.north / .south / .east / .west should return the wall of the cell
# - map.getCell(1, 1).south should be the same wall as map.getCell(1, 2).north


# Create map:
# - map = TarjanMap(10, 10) should create a new map of size 10, 10

class MapCreation(unittest.TestCase):
    def testCreateMap(self):
        "maps should be created without error, and have correct width / height after creation."
        w = 8
        h = 8
        map = TarjanMap.TarjanMap(w, h)
        self.assertEqual(map.width, w)
        self.assertEqual(map.height, h)

    def testMapInitalization(self):
        "maps should be initialized with empty string for all walls and floors"
        w = 8
        h = 8
        map = TarjanMap.TarjanMap(w, h)

        for x, y in [(x, y) for y in xrange(h) for x in xrange(w)]:
            self.assertEqual(map.getCell(x, y).floor, "")
            self.assertEqual(map.getCell(x, y).north, "")
            self.assertEqual(map.getCell(x, y).south, "")
            self.assertEqual(map.getCell(x, y).east, "")
            self.assertEqual(map.getCell(x, y).west, "")

class CellSanity(unittest.TestCase):
    def setUp(self):
        self.map = TarjanMap.TarjanMap()

    def testCellSanity(self):
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            cell.setFloor(str((x,y)))
            self.assertEqual(cell.getFloor(), str((x,y)))

    def testWallSanity(self):
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            for direction in Directions:
                cell.setWall(direction, str((x,y)))
                self.assertEqual(cell.getWall(direction), str((x,y)))

    def testFloorProperty(self):
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            "cell.floor should work like cell.set/getFloor()"
            cell.setFloor(str((x,y)))
            self.assertEqual(cell.floor, str((x,y)))
            cell.floor = "_" + str((x,y))
            self.assertEqual(cell.getFloor(), "_" + str((x,y)))

    def testNotesProperty(self):
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            "cell.notes should work like cell.set/getNotes()"
            cell.setNotes(str((x,y)))
            self.assertEqual(cell.notes, str((x,y)))
            cell.notes = "_" + str((x,y))
            self.assertEqual(cell.getNotes(), "_" + str((x,y)))

    def testWallProperties(self):
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            "cell.north, .south, etc. should work like cell.set/getWall()"
            for direction in Directions:
                s = str(direction) + str((x,y))
                cell.setWall(direction, s)
                if (direction == Directions.north):
                    self.assertEqual(cell.north, s)
                    cell.north = "_" + s
                elif (direction == Directions.east):
                    self.assertEqual(cell.east, s)
                    cell.east = "_" + s
                elif (direction == Directions.south):
                    self.assertEqual(cell.south, s)
                    cell.south = "_" + s
                else:
                    self.assertEqual(cell.west, s)
                    cell.west = "_" + s
                self.assertEqual(cell.getWall(direction), "_" + s)

class CellAndWallConnectivity(unittest.TestCase):

    def setUp(self):
        self.map = TarjanMap.TarjanMap()

    def process(self, verify):
        "for all walls, call function 'verify' with arguments cell1, cell2 and wall direction"
        for x,y in [(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            cur = self.map.getCell(x,y)
            if (x > 0): verify(cur, self.map.getCell(x - 1, y), Directions.west)
            if (x < self.map.width - 1): verify(cur, self.map.getCell(x + 1, y), Directions.east)
            if (y > 0): verify(cur, self.map.getCell(x, y - 1), Directions.north)
            if (y < self.map.height - 1): verify(cur, self.map.getCell(x, y + 1), Directions.south)

    def testWallConnectivity(self):
        "Walls between cell must map to the same wall"
        def verify(cell1, cell2, dir):
            orig = cell1.getWall(dir)
            assert cell2.getWall(~dir) == orig
            cell2.setWall(~dir, orig + 'TEST')
            assert cell1.getWall(dir) == orig + 'TEST'
            cell1.setWall(dir, orig)
            assert cell2.getWall(~dir) == orig
        self.process(verify)

class CopyPasteFunctionality(unittest.TestCase):

    def setUp(self):
        "create a map, and initialize all walls and cells to unique values"
        self.map = TarjanMap.TarjanMap()
        for cell in [self.map.getCell(x,y) for y in xrange(self.map.height) for x in xrange(self.map.width)]:
            cell.floor = str((cell.x, cell.y))
            for direction in Directions:
                cell.setWall(direction, str(direction) + str((cell.x, cell.y)))

    def compare(self, other, x, y):
        "compare self.map to other, starting at self.map(x, y) and using other width and height. True if equal"
        for dx, dy in [(dx, dy) for dy in xrange(other.height) for dx in xrange(other.width)]:
            cell1 = self.map.getCell(x + dx, y + dy)
            cell2 = other.getCell(dx, dy)
            self.assertEqual( cell1.floor, cell2.floor )
            for direction in Directions:
                self.assertEqual( cell1.getWall(direction), cell2.getWall(direction) )

    def testGetCompleteMap(self):
        "getting the entire map should return a one-to-one copy of original map"
        copy = self.map.getMap(0, 0, self.map.width, self.map.height)
        self.compare(copy, 0, 0)
        # this is mostly to make sure the compare function works
        self.assertEqual( copy.floors, self.map.floors )
        self.assertEqual( copy.walls, self.map.walls )
        
    def testGetSubset(self):
        "getting a subset should get a correct copy of the area"
        self.compare(self.map.getMap(3, 3, 3, 4), 3, 3)

    def testSetCompleteMap(self):
        "set the entire map to an empty map should empty the entire map"
        other = TarjanMap.TarjanMap()
        self.map.setMap(other, 0, 0)
        self.compare(other, 0, 0)
        # this is mostly to make sure the compare function works
        self.assertEqual( other.floors, self.map.floors )
        self.assertEqual( other.walls, self.map.walls )

class Notifications(unittest.TestCase):

    class Observer(TarjanObservable):
        item = None,
        def update(self, *args):
            self.item = args
    
    def setUp(self):
        "create a map and attach observer"
        self.map = TarjanMap.TarjanMap()
        self.observer = self.Observer()
        self.map.attach(self.observer)

    def testFloorChange(self):
        self.map.getCell(5,5).floor = "hest"
        self.assertEqual(self.observer.item, (5,5))
        

if __name__ == "__main__":
    unittest.main() 

